package com.cnhis.drgs.util;

import com.cnhis.drgs.vo.KeyValue;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cglib.beans.BeanMap;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 常用工具类
 *
 * @author andLevy
 * @date 2020年4月14日
 */
public class Util {

    private static Log logger = LogFactory.getLog(Util.class);


    /**
     * 判断Map是否为空
     *
     * @param map
     * @return
     */
    public static boolean isMapNotEmpty(Map<?, ?> map) {
        return map != null && map.size() > 0;
    }

    /**
     * 判断集合是否为空
     *
     * @param collection
     * @return
     */
    public static boolean isCollectionNotEmpty(Collection<?> collection) {
        return collection != null && collection.size() > 0;
    }

    /**
     * 判断数组是否为空
     *
     * @param arr
     * @return
     */
    public static boolean isArrayNotEmpty(Object[] arr) {
        return arr != null && arr.length > 0;
    }

    /**
     * 快速组装Map
     *
     * @param kvs
     * @return
     */
    public static Map<String, Object> getSimpleMap(KeyValue... kvs) {
        Map<String, Object> map = new HashMap<>();
        if (kvs != null) {
            for (KeyValue kv : kvs) {
                map.put(kv.getKey() + "", kv.getValue());
            }
        }
        return map;
    }

    /**
     * 获取客户端真实ip
     *
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }


    /*
     * javabean与map的转换有很多种方式，比如:
     *
     * 1、通过ObjectMapper先将bean转换为json，再将json转换为map，但是这种方法比较绕，且效率很低，经测试，循环转换10000个
     * bean，就需要12秒！！！不推荐使用
     *
     * 2、通过java反射，获取bean类的属性和值，再转换到map对应的键值对中，这种方法次之，但稍微有点麻烦
     *
     * 3、通过net.sf.cglib.beans.BeanMap类中的方法，这种方式效率极高，它跟第二种方式的区别就是因为使用了缓存，初次创建
     * bean时需要初始化，之后就使用缓存，所以速度极快，经测试，循环bean和map的转换10000次，仅需要300毫秒左右。
     */



    /**
     * 将对象装换为map
     *
     * @param bean
     * @param properties 自定义属性
     * @return
     */
    public static Map<String, Object> objectToMap(Object bean, String... properties) {
        Map<String, Object> map = new HashMap<>();
        if (bean != null) {
            BeanMap beanMap = BeanMap.create(bean);
            for (String property : properties) {
                map.put(property + "", beanMap.get(property));
            }
        }
        return map;
    }


    /**
     * 将map装换为javabean对象
     *
     * @param map
     * @param bean
     * @return
     */
    public static <T> T mapToObject(Map<String, Object> map, T bean) {
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }


    /**
     * 将 List<Map<String, Object>> 装换为List<Object>对象
     *
     * @param maps
     * @param bean
     * @return
     */
    public static <T> List<T> mapListToObjects(List<Map<String, Object>> maps, T bean) {
        List<T> objectList = new ArrayList<>();
        if (Util.isCollectionNotEmpty(maps)) {
            for (Map<String, Object> map : maps) {
                BeanMap beanMap = BeanMap.create(bean);
                beanMap.putAll(map);
                objectList.add(bean);
            }
        }
        return objectList;
    }


    /**
     * 将List<T>转换为List<Map<String, Object>>
     *
     * @param beanList
     * @param properties  自定义属性
     * @return
     */
    public static <T> List<Map<String, Object>> objectListToMaps(List<T> beanList, String... properties) {
        List<Map<String, Object>> list = new ArrayList<>();
        if (Util.isCollectionNotEmpty(beanList)) {
            for (Object object : beanList) {
                list.add(objectToMap(object, properties));
            }
        }
        return list;
    }


    /**
     * 删除对象部分属性
     *
     * @param bean       目标对象
     * @param properties 要删除的属性
     * @return Map<String, Object>
     */
    public static Map<String, Object> delObjectToMap(Object bean, String... properties) {
        Map<String, Object> map = new HashMap<>();
        if (bean != null) {
            BeanMap beanMap = BeanMap.create(bean);
            for (Object key : beanMap.keySet()) {
                map.put(key + "", beanMap.get(key));
                if (Util.isArrayNotEmpty(properties)) {
                    for (String property : properties) {
                        if (property.equals(key)) {
                            map.keySet().removeIf(k->k.equals(property));
                        }
                    }

                }
            }
        }
        return map;
    }


    /**
     * 删除List<T>里的对象部分属性，封装成List<Map<String,Object>>
     *
     * @param beans      目标对象集合
     * @param properties 要删除的属性
     * @return List<Map < String, Object>>
     */
    public static <T> List<Map<String, Object>> delObjectListToMaps(List<T> beans, String... properties) {
        List<Map<String, Object>> list = new ArrayList<>();
        if (Util.isCollectionNotEmpty(beans)) {
            for (Object bean : beans) {
                list.add(delObjectToMap(bean, properties));
            }
        }
        return list;
    }


    /**
     * 获取两个纳秒间隔时间
     *
     * @return
     */
    public static BigDecimal getIntervalTime(long startTime, long endTime) {
        //long time1 = System.nanoTime();

        // do work

        //long time2 = System.nanoTime();
        return BigDecimal.valueOf((double) (endTime - startTime) / 1000000000).setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 获取两个纳秒间隔时间
     *
     * @return
     */
    public static BigDecimal getIntervalTime(long startTime) {
        //long time1 = System.nanoTime();

        // do work

        //long time2 = System.nanoTime();
        return BigDecimal.valueOf((double) (System.nanoTime() - startTime) / 1000000000).setScale(2, BigDecimal.ROUND_HALF_UP);
    }


    public static List listUnion(List... list) {
        List<?> result = null;
        if (isArrayNotEmpty(list)) {
            for (int i = 0; i < list.length; i++) {
                if (i == 0) {
                    if (list[i] == null) {
                        result = new ArrayList<>();
                    } else {
                        result = new ArrayList<>(list[i]);
                    }
                } else {
                    result.addAll(list[i]);
                }
            }
        }
        return result;
    }


    //参数占位符正则
    private static final String PARAMS_REG = "\\$\\{\\w*\\}";

    /**
     * 填充模板消息
     * <p>
     * eg: 尊敬的${username}，感谢使用xx系统！
     * </p>
     *
     * @param templateMessage
     * @param params
     * @return
     */
    public static String fillTemplateMessage(String templateMessage, Map<String, Object> params) {
        if (StringUtils.isBlank(templateMessage)) {
            return null;
        }
        if (params == null || params.isEmpty()) {
            //logger.warn("参数为空");
            return templateMessage;
        }
        Pattern pattern = Pattern.compile(PARAMS_REG);
        Matcher matcher = pattern.matcher(templateMessage);
        matcher.reset();
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String str = matcher.group();
            String key = str.substring(2, str.length() - 1);
            Object value = params.get(key);
            if (value == null) {
                logger.warn("找不到参数[" + key + "]对应的值，请检查参数列表：" + params);
            }
            matcher.appendReplacement(sb, value == null ? "" : value.toString());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }


}
